use chrono::NaiveDate;
use serde_json::{from_str, from_value, Value};
use std::collections::HashMap;

pub fn check_id_card(id_card_no: &str) -> String {
    let region = std::fs::read_to_string("code.json").unwrap();
    let region: Value = from_str(&region).unwrap();
    let region: HashMap<String, String> = from_value(region).unwrap();
    let err = "Wrong ID Number";

    let id_card_no = if id_card_no.len() == 15 {
        match convert_to_18_digits(id_card_no) {
            Some(new_id_card) => new_id_card,
            None => return "无法将15位身份证号码转换为18位".to_string(),
        }
    } else if id_card_no.len() == 18 {
        id_card_no.to_string()
    } else {
        return "身份证号码错误".to_string();
    };
    if !id_card_no[..17].chars().all(|c| c.is_digit(10)) {
        return err.to_string();
    }

    // 检查第18位是否为数字或X
    let last_char = id_card_no.chars().nth(17).unwrap();
    if !last_char.is_digit(10) && last_char != 'X' && last_char != 'x' {
        return err.to_string();
    }

    // 检查出生日期是否有效
    let year = match id_card_no[6..10].parse::<i32>() {
        Ok(year) => year,
        Err(_) => return "无效的年份".to_string(),
    };
    let month = match id_card_no[10..12].parse::<u32>() {
        Ok(month) => month,
        Err(_) => return "无效的月份".to_string(),
    };
    let day = match id_card_no[12..14].parse::<u32>() {
        Ok(day) => day,
        Err(_) => return "无效的日期".to_string(),
    };
    match NaiveDate::from_ymd_opt(year, month, day) {
        Some(date) => date,
        None => return "无效的出生日期".to_string(),
    };
    
    let province_str = match validate_province(&id_card_no, &region) {
        Ok(province) => province,
        Err(_) => {
            return err.to_string();
        }
    };

    let city_str = match validate_city(&id_card_no, &region) {
        Ok(city) => city,
        Err(_) => {
            return err.to_string();
        }
    };

    let district_str = match validate_district(&id_card_no, &region) {
        Ok(district) => district,
        Err(_) => {
            return err.to_string();
        }
    };

    // 检查校验码
    let factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
    let sum: u32 = id_card_no[..17].chars()
        .zip(factors.iter())
        .map(|(c, &f)| c.to_digit(10).unwrap() * f)
        .sum();

    let expected_check_code = check_codes[(sum % 11) as usize];
    if last_char.to_ascii_uppercase() != expected_check_code {
        return "身份证号码错误".to_string();
    }

    // 提取性别
    let gender = get_gender(&id_card_no);
    let formatted_birth_date = format!("{:04}年{:02}月{:02}日", year, month, day);
    format!(
        "身份证号码正确,{},{},{}-{}-{}",
        gender, formatted_birth_date, province_str, city_str, district_str
    )
}
fn get_gender(id: &str) -> String {
    let idx = if id.len() == 15 { 14 } else { 16 };

    let c = id.chars().nth(idx).unwrap().to_digit(10).unwrap();
    if c % 2 == 0 {
        "女".to_string()
    } else {
        "男".to_string()
    }
}
    // convert 15 id card number to 18
fn convert_to_18_digits(id_card: &str) -> Option<String> {
        if id_card.len() != 15 {
            return None;
        }
    
        let year = format!("19{}", &id_card[6..8]);
        let new_id_card = format!("{}{}{}", &id_card[0..6], year, &id_card[8..15]);
    
        let factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
        let sum: u32 = new_id_card.chars()
            .zip(factors.iter())
            .map(|(c, &f)| c.to_digit(10).unwrap() * f)
            .sum();
    
        let check_code = check_codes[(sum % 11) as usize];
        Some(format!("{}{}", new_id_card, check_code))
}

fn validate_province(id: &str, region: &HashMap<String, String>) -> Result<String, ()> {
    let province_code = &id[0..2];
    let province_code = format!("{}0000", province_code);
    match region.get(&province_code) {
        Some(province) => {
            if province != " " {
                Ok(province.clone())
            } else {
                Err(())
            }
        }
        None => Err(()),
    }
}

fn validate_city(id: &str, region: &HashMap<String, String>) -> Result<String, ()> {
    let city_code = &id[0..4];
    let city_code = format!("{}00", city_code);
    match region.get(&city_code) {
        Some(city) => {
            if city != " " {
                Ok(city.clone())
            } else {
                Err(())
            }
        }
        None => Err(()),
    }
}

fn validate_district(id: &str, region: &HashMap<String, String>) -> Result<String, ()> {
    let district_code = &id[0..6];
    match region.get(district_code) {
        Some(district) => {
            if district != " " {
                Ok(district.clone())
            } else {
                Err(())
            }
        }
        None => Err(()),
    }
}
